using System;
using System.Runtime.CompilerServices;
using System.Serialization;

namespace Nsb.Classes
{
    [IgnoreNamespace]
    public static class Strings
    {
        public static readonly RegularExpression SafeFileNameRx = (RegularExpression) Script.Literal(@"/[^\w\d.-]+/g");

        private static readonly RegularExpression RxSquish = new RegularExpression(@"\s", "g");

        public static string ParaCase(string s)
        {
            return s != null ? s.Substr(0, 1).ToUpperCase() + s.Substr(1) : "";
        }

        public static string SafeFileName(string n)
        {
            return n != null ? n.Replace("&nbsp;", " ").ReplaceRegex(SafeFileNameRx, "_").ToLowerCase() : "";
        }

        public static string ParaSquishCase(string s)
        {
            return s != null ? ParaCase(s.ReplaceRegex(RxSquish, "")) : "";
        }

        public static object FnStringify(object item)
        {
            return
                Json.Stringify(
                    item,
                    delegate(string n, object v) { return Type.GetScriptType(v) == "function" ? v.ToString() : v; }
                    );
        }

        // selected tags [1], < and > [2&3], and html special characters [4]
        // <span> is the only tag that allows attributes
        private static readonly RegularExpression AllowedTagsRx = (RegularExpression)Script.Literal(@"/(<\/?(?:b|i|u|em|h[0-9]|p|blockquote|abbr|acronym|address|cite|code|del|dfn|sub|sup|strike|big|small|pre|xmp|strong|ul|ol|li|dl|dt|dd|span(?:\s[^>]*)?|img(?:\s[^>]+))>)|(<)|(>)|(&(?:#[0-9]+|[a-z]+);|&)/gi");
        
        public static string SanitizeTags(string txt)
        {
            int idx = AllowedTagsRx.LastIndex = 0;
            string ot = "";

            string[] mm = AllowedTagsRx.Exec(txt);
            while (mm != null)
            {
                int st = AllowedTagsRx.LastIndex - mm[0].Length;
                if (st > idx)
                    ot += txt.Substring(idx, st);
                if (mm[4] != null)
                    ot += mm[4].Length > 1 ? mm[4] : "&amp;";
                else if (mm[3] != null)
                    ot += "&gt;";
                else if (mm[2] != null)
                    ot += "&lt;";
                else if (mm[1] != null)
                    ot += mm[1]/*.ToLowerCase()*/; // TODO: allow ToLowerCase() which incorrectly lowers <span> tag attributes as well
                idx = AllowedTagsRx.LastIndex;
                mm = AllowedTagsRx.Exec(txt);
            }
            if (idx < txt.Length)
                ot += txt.Substr(idx);
            return ot;
        }

        /// <summary>
        /// Reduces multiple spaces on front or end to single spaces
        /// </summary>
        /// <param name="txt">string to reduce</param>
        /// <returns>reduced string</returns>
        public static string Reduce(string txt)
        {
            return txt.ReplaceRegex((RegularExpression)Script.Literal(@"/^\s+|\s+$/g"), " ");
        }

        public static string Times(int t, string txt)
        {
            string ot = "";
            while ((t--) > 0)
                ot += txt;
            return ot;
        }

    }
}